#include<stdio.h>
#include <conio.h>
#include <sys/stat.h>
#include<windows.h>
#include<stdlib.h>
#define BufferSize 64*1024
#pragma execution_character_set("utf-8")
#pragma comment(lib,"winmm.lib")
#pragma pack (4)
#pragma pack ()
unsigned char *databuf;
#define instr_type 0
#define rdata_type 1

unsigned int instr_switch = 0;
unsigned int rdata_switch = 0;
unsigned int wdata_switch = 0;
int usart_send(HANDLE COM,void*pbuf,unsigned int len,DWORD *iLen)
{
	//EnterCriticalSection(&cs);
	WriteFile(COM,pbuf,len,iLen,NULL);
	//LeaveCriticalSection(&cs);
	return 0;
}

void cpu_write_data(unsigned char wb,unsigned short addr,unsigned int data)
{
    // printf("wd %x addr = 0x%08x data = 0x%08x\r\n",wb,addr,data);
    if(wb == 0x01)
    {
        if(addr == 0x1000)
           putchar((char)(data));
    }
    if(wb == 0xf)
    {
        
    }
    if(addr == 0x5a4)
    {
        
    }

}

void cpu_read_data(unsigned short addr,unsigned int data)
{
    // printf("read addr 0x%08x data:0x%08x\r\n",addr,data);
     if(addr  == 0x114)
     {
        
     }

}

void cpu_fetch_instr(unsigned short addr,unsigned int data)
{
    // printf("instr addr 0x%08x data 0x%08x\r\n",addr,data);
    if(addr == 0x88)
    {
        //system("PAUSE");
    }
    if(addr < 0x10000)
    {
        //printf("instr addr 0x%08x\r\n",addr);
    }
}
void usart_recv(HANDLE COM,unsigned char *pbuf,unsigned int len)
{
    DWORD iLen;
    DWORD rCount;
    unsigned int i=0;
    BOOL bReadStat;
    iLen = len;
    unsigned int count=0;
    while(1)
    {
        bReadStat = ReadFile(COM,pbuf + i,iLen,&rCount,NULL);
        if(bReadStat)
        {
            count += rCount;
            i = count - 1;
            iLen = len - iLen;
        }
        if(count == len)
        {
            break;
        }
    }
    
}
void display_buf(unsigned char buf[],unsigned int len)
{
    unsigned int i,temp;
    for(i=0;i<len;i+=4)
    {
        printf("0x%04x:",i);
        temp = (buf[i+3] << 24)|(buf[i+2] << 16)|(buf[i+1] << 8)|buf[i+0];
        printf("0x%08x\r\n",temp);
    }
}
void display_hex(unsigned char buf[],unsigned int len)
{
    unsigned int i;
    puts("cmd hex:");
    for(i=0;i<len;i++)
    {
        printf("0x02x ",buf[i]);
    }
    puts("");
}
unsigned int cpu_first_fetch = 0;
void main(unsigned int argc,char*argv[])
{
    unsigned int mem_type;
    unsigned char buf[16];
    size_t fileRDsize;
    unsigned int i;
    unsigned int inscode;
    unsigned int wdata;
    unsigned int rdata;
    unsigned short addr;
    unsigned char wb;
    DWORD wCount;
    unsigned int pcount;
    HANDLE hComm;
    long int filelen;
    FILE *f;
	BOOL bReadStat;
    COMMTIMEOUTS TimeOuts;
	DCB usart1;
    if(argc < 2)
    {
        printf("input parameter less than two\r\n");
        return;
    }
    hComm = CreateFile(argv[1],GENERIC_READ|GENERIC_WRITE,
	0, NULL, OPEN_EXISTING, 0, 0);
    if(hComm==(HANDLE)-1)
	{
		printf("serial %s open fail\r\n",argv[1]);
		return ;
	}
    f = fopen(argv[2],"rb");
    if(f == NULL)
    {
        CloseHandle(hComm);
        printf("file %s open fail\r\n");
        return;
    }
    fseek(f, 0, SEEK_END);
    filelen = ftell(f);
    fileRDsize = (size_t)filelen;
    fseek(f, 0, SEEK_SET);
    printf("%s filesize %d\r\n",argv[2],fileRDsize);
    databuf = (unsigned char*)malloc(BufferSize);
    for(i = 0; i<fileRDsize;i+=4)
    {
        fread(databuf+i,4,1,f);
    }
    //display_buf(databuf,filelen);
    SetupComm(hComm,1024,1024);
/*	TimeOuts.ReadIntervalTimeout=0;
	TimeOuts.ReadTotalTimeoutMultiplier=500;
	TimeOuts.ReadTotalTimeoutConstant=500;//设定写超时
	TimeOuts.WriteTotalTimeoutMultiplier=0;
	TimeOuts.WriteTotalTimeoutConstant=500;
	SetCommTimeouts(hComm,&TimeOuts);*/
	GetCommState(hComm,&usart1);
	usart1.BaudRate=115200;
	usart1.StopBits=ONESTOPBIT;
	usart1.Parity=NOPARITY;
	usart1.ByteSize=8;
	SetCommState(hComm,&usart1);	
	PurgeComm(hComm,PURGE_TXCLEAR|PURGE_RXCLEAR);
    puts("");
    buf[0]=0x00;
    buf[1]=0x00;
    buf[2]=0x00;
    buf[3]=0x67;
    //usart_send(hComm,buf,4,&wCount);//发送jalr x0,0(x0)指令使CPU复位
    //Sleep(1000);
    //usart_send(hComm,buf,4,&wCount);
    while(1)
    {
        if(_kbhit())
        {
            int key;
            key = _getch();
            switch(key)
            {
                case 'i':
                    instr_switch ^= 1;
                    printf("instr_switch %d\r\n",instr_switch);
                    break;
                case 'r':
                    rdata_switch ^= 1;
                    break;
                case '0':
                    wdata_switch = 0;
                    break;
                case '1':
                    wdata_switch = 1;
                    break;
                case '2':
                    wdata_switch = 2;
                    break;
                case '3':
                    wdata_switch = 3;
                    break;
                default:
                    printf("\r\nkey code %d\r\n",key);
                    break;
            }

        }
        bReadStat=ReadFile(hComm,buf,1,&wCount,NULL);
        if(bReadStat)
        {
            
            if(0xfe == buf[0])
            {
                f = fopen(argv[2],"rb");
                if(f == NULL)
                {
                    CloseHandle(hComm);
                    printf("file %s open fail\r\n");
                    return;
                }
                fseek(f, 0, SEEK_END);
                filelen = ftell(f);
                fileRDsize = (size_t)filelen;
                fseek(f, 0, SEEK_SET);
                free(databuf);
                databuf = (unsigned char*)malloc(BufferSize);
                for(i = 0; i<fileRDsize;i+=4)
                {
                    fread(databuf+i,4,1,f);
                }
                system("cls");
                cpu_first_fetch = 0;
                continue;
            }
            else if((0x80 == buf[0])||(0xA0 == buf[0]))
            {
                // do
                // {
                //     bReadStat=ReadFile(hComm,buf,2,&wCount,NULL);
                //     if(bReadStat)
                //     {
                //         if(wCount == 2)
                //         {
                //             addr = (buf[0] << 8)|(buf[1]);
                //             addr = addr >> 2;
                //             printf("rd 0x%x\r\n",addr);
                //         }
                //         else
                //         {
                //             printf("read data get adr error\r\n");
                //         }
                //     }
                // } while (!bReadStat);
                
                if(0x80 == buf[0])
                {
                    mem_type = instr_type;
                    // puts("ins #");
                }
                else
                {
                    mem_type = rdata_type;
                    // puts("rdata #");
                }
                usart_recv(hComm,buf,2);
                addr = (buf[0] << 8)|(buf[1]);
                addr = addr >> 2;
                buf[0] = 0;
                buf[1] = 0;
                buf[2] = 0;
                buf[3] = 0;
                
                buf[0] = (databuf[addr*4 + 3]&0xff);
                buf[1] = (databuf[addr*4 + 2]&0xff);
                buf[2] = (databuf[addr*4 + 1]&0xff);
                buf[3] = (databuf[addr*4 + 0]&0xff);
                // if(cpu_first_fetch == 0)
                // {
                //     buf[0]=0x00;
                //     buf[1]=0x00;
                //     buf[2]=0x00;
                //     buf[3]=0x67;
                //     if(mem_type == instr_type)
                //         cpu_first_fetch = 1;
                // }
                rdata = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
                inscode = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
                usart_send(hComm,buf,4,&wCount);
                
                
                if( instr_type== mem_type)
                {
                    cpu_fetch_instr(addr << 2,inscode);
                    if(instr_switch)
                    {
                        printf("instr [0x%08x] = 0x%08x ok\r\n",addr << 2,inscode);
                    }

                }
                if( rdata_type== mem_type)
                {
                    cpu_read_data(addr << 2,rdata);
                    if(rdata_switch)
                    {
                        printf("read data [0x%08x] = 0x%08x ok\r\n",addr << 2,rdata);
                    }
                }
            }
            else if(0x90 == (buf[0]&0x90))
            {
                wb = buf[0]&0x0f;
                usart_recv(hComm,buf,2);
                addr = (buf[0] << 8)|(buf[1]);
                addr = addr >> 2;
                if(wb == 0x0f)
                {
                    usart_recv(hComm,buf,4);
                    databuf[addr*4 + 3] = buf[0];
                    databuf[addr*4 + 2] = buf[1];
                    databuf[addr*4 + 1] = buf[2];
                    databuf[addr*4 + 0] = buf[3];
                    wdata = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | (buf[3] << 0);
                    cpu_write_data(wb,addr << 2,wdata);
                    if(wdata_switch>2)
                    {
                        printf("wb = 0x%x [0x%08x] write word 0x%x\r\n",wb,addr << 2,wdata);
                    }       
                }
                else if((0x01 == wb)
                        ||(0x02 == wb)
                        ||(0x04 == wb)
                        ||(0x08 == wb))
                {
                    usart_recv(hComm,buf,1);
                    switch(wb)
                    {
                        case 1:
                            if(addr*4 == 0x1000)
                            {
                                break;
                            }
                            databuf[addr*4 + 0] = buf[0];
                            break;
                        case 2:
                            databuf[addr*4 + 1] = buf[0];
                            break;
                        case 4:
                            databuf[addr*4 + 2] = buf[0];
                            break;
                        case 8:
                            databuf[addr*4 + 3] = buf[0];
                            break;
                        default:
                            printf("sb error:this code shouldn't exec\r\n");
                            break;
                    }
                    wdata = (buf[0] << 0);
                    cpu_write_data(wb,addr << 2,wdata);
                    if(wdata_switch>0)
                    {
                        printf("wb = 0x%x [0x%08x] write byte 0x%x\r\n",wb,addr << 2,wdata);
                    }
                }
                else if((0x03 == wb) || (0x0c == wb))
                {
                    usart_recv(hComm,buf,2);
                    switch(wb)
                    {
                        case 0x03:
                            databuf[addr*4 + 1] = buf[0];
                            databuf[addr*4 + 0] = buf[1];
                            break;
                        case 0x0c:
                            databuf[addr*4 + 3] = buf[0];
                            databuf[addr*4 + 2] = buf[1];
                            break;
                        default:
                            printf("sh error:this code shouldn't exec\r\n");
                            break;
                    }
                    wdata = (buf[0] << 8) | (buf[1] << 0);
                    cpu_write_data(wb,addr << 2,wdata);
                    if(wdata_switch>1)
                    {
                        printf("wb = 0x%x [0x%08x] write halfword 0x%04x\r\n",wb,addr << 2,wdata);
                    }
                }
                else
                {
                    printf("sb error: wb = 0x%x addr = 0x%x\r\n",wb,addr << 2);
                }
            }
        }
    }
	fclose(f);
}
